using Newtonsoft.Json;
using System;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.Xml.Serialization;

namespace ParallelLib.Micro
{
    [DataContract]
    [Description]
    [Serializable]
    [XmlRoot]
    public class BeaconNode
    {
        public BeaconNode()
        {
            this.HostApp = AppDomain.CurrentDomain.FriendlyName;
        }

        [XmlElement]
        [DataMember]
        [Description]
        [JsonProperty]
        public string Id { get; set; }

        [DataMember]
        [Description]
        [JsonProperty]
        public string Name { get; set; }

        [DataMember]
        [Description]
        [JsonProperty]
        public string Type { get; set; }

        [DataMember]
        [Description]
        [JsonProperty]
        public string Group { get; set; }

        [DataMember]
        [Description]
        [JsonProperty]
        [JsonIgnore]
        public string Address { get; set; }

        [DataMember]
        [Description]
        [JsonProperty]
        [JsonIgnore]
        public string HostName { get; set; }

        [DataMember]
        [Description]
        [JsonProperty]
        [JsonIgnore]
        public string HostApp { get; set; }

        [DataMember]
        [Description]
        [JsonProperty]
        [JsonIgnore]
        private string _arguments;

        [DataMember]
        [Description]
        [JsonProperty]
        [JsonIgnore]
        public string Arguments
        {
            get { return _arguments; }
            set
            {
                if (_arguments == value) return;
                _arguments = value;
                OnArgumentsChanged();
            }
        }

        public string GetHostAddress()
        {
            var i = Address.IndexOf(':');
            return i == -1 ? Address : Address.Substring(0, i);
        }

        public event Action<BeaconNode> ArgumentsChanged;

        private void OnArgumentsChanged()
        {
            ArgumentsChanged?.Invoke(this);
        }

        protected bool Equals(BeaconNode other)
        {
            if (other == null)
                return false;
            return string.Equals(JsonConvert.SerializeObject(this), JsonConvert.SerializeObject(other));
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) 
                return false;
            if (ReferenceEquals(this, obj)) 
                return true;
            if (obj.GetType() != this.GetType()) 
                return false;
            return Equals((BeaconNode)obj);
        }

        public override int GetHashCode()
        {
            return this.ToString().GetHashCode();
        }

        public override string ToString()
        {
            return string.Format("{0}.{1}.{2}.{3}?{4}", Group, Type, Name, Address, Arguments);
        }

        public void Clone(BeaconNode node)
        {
            if (node == null) 
                return;
            this.Address = node.Address;
            this.Arguments = node.Arguments;
            this.Group = node.Group;
            this.HostApp = node.HostApp;
            this.HostName = node.HostName;
            this.Name = node.Name;
            this.Type = node.Type;
            this.Id = node.Id;
        }

        public string Serialize()
        {
            return JsonConvert.SerializeObject(this);
        }

        public void Deserialize(string jsonValue)
        {
            if (string.IsNullOrEmpty(jsonValue)) 
                return;
            try
            {
                BeaconNode node = JsonConvert.DeserializeObject<BeaconNode>(jsonValue);
                this.Clone(node);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Trace.TraceError(ex.Message);
            }
        }

        public MQConfig GetConfig()
        {
            if (string.IsNullOrEmpty(this.Arguments)) 
                return null;
            return JsonConvert.DeserializeObject<MQConfig>(this.Arguments);
        }

        public string GetWebUrl()
        {
            var config = this.GetConfig();
            if (config == null)
                return string.Empty;
            return string.Format("http://{0}:{1}/{2}", this.GetHostAddress(), config.WebPort, config.BaseUri);
        }
    }
}